#include "file_utils.h"
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>

#ifdef _WIN32
#include <windows.h>
#include <direct.h>
#define mkdir(path, mode) _mkdir(path)
#define stat _stat
#else
#include <sys/types.h>
#include <fcntl.h>
#endif

// 创建目录（递归）
bool create_directory_recursive(const char *path)
{
    char tmp[MAX_PATH_LEN];
    char *p = NULL;
    size_t len;

    snprintf(tmp, sizeof(tmp), "%s", path);
    len = strlen(tmp);
    if (tmp[len - 1] == '/')
    {
        tmp[len - 1] = 0;
    }

    for (p = tmp + 1; *p; p++)
    {
        if (*p == '/')
        {
            *p = 0;
#ifdef _WIN32
            if (_access(tmp, 0) {
                if (mkdir(tmp) return false;
            }
#else
            if (access(tmp, F_OK))
            {
                if (mkdir(tmp, 0755))
                    return false;
            }
#endif
            *p = '/';
        }
    }

#ifdef _WIN32
    if (_access(tmp, 0))
    {
        return mkdir(tmp) == 0;
    }
#else
    if (access(tmp, F_OK))
    {
        return mkdir(tmp, 0755) == 0;
    }
#endif

    return true;
}

// 删除目录（递归）
bool delete_directory_recursive(const char *path)
{
    DIR *d = opendir(path);
    size_t path_len = strlen(path);
    int r = -1;

    if (d)
    {
        struct dirent *p;
        r = 0;

        while (!r && (p = readdir(d)))
        {
            int r2 = -1;
            char *buf;
            size_t len;

            /* Skip the names "." and ".." as we don't want to recurse on them. */
            if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, ".."))
            {
                continue;
            }

            len = path_len + strlen(p->d_name) + 2;
            buf = malloc(len);

            if (buf)
            {
                struct stat statbuf;
                snprintf(buf, len, "%s/%s", path, p->d_name);

                if (!stat(buf, &statbuf))
                {
                    if (S_ISDIR(statbuf.st_mode))
                    {
                        r2 = delete_directory_recursive(buf);
                    }
                    else
                    {
#ifdef _WIN32
                        r2 = remove(buf);
#else
                        r2 = unlink(buf);
#endif
                    }
                }
                free(buf);
            }
            r = r2;
        }
        closedir(d);
    }

    if (!r)
    {
#ifdef _WIN32
        r = _rmdir(path);
#else
        r = rmdir(path);
#endif
    }

    return r == 0;
}

// 获取文件大小
long get_file_size(const char *path)
{
    struct stat st;
    if (stat(path, &st) == 0)
    {
        return st.st_size;
    }
    return -1;
}

// 获取文件修改时间
time_t get_file_mtime(const char *path)
{
    struct stat st;
    if (stat(path, &st) == 0)
    {
        return st.st_mtime;
    }
    return 0;
}

// 构建完整路径
char *build_full_path(const char *base, const char *subpath)
{
    char *path = malloc(MAX_PATH_LEN);
    if (!path)
        return NULL;

    snprintf(path, MAX_PATH_LEN, "%s/%s", base, subpath);
    return path;
}

// 文件是否存在
bool file_exists(const char *path)
{
#ifdef _WIN32
    return _access(path, 0) == 0;
#else
    return access(path, F_OK) == 0;
#endif
}

// 复制文件
bool copy_file(const char *src, const char *dest)
{
    FILE *source = fopen(src, "rb");
    if (!source)
        return false;

    FILE *destination = fopen(dest, "wb");
    if (!destination)
    {
        fclose(source);
        return false;
    }

    char buffer[4096];
    size_t bytes;
    while ((bytes = fread(buffer, 1, sizeof(buffer), source)) > 0)
    {
        fwrite(buffer, 1, bytes, destination);
    }

    fclose(source);
    fclose(destination);
    return true;
}

// 移动文件
bool move_file(const char *src, const char *dest)
{
    if (rename(src, dest) == 0)
    {
        return true;
    }

    // 如果重命名失败，尝试复制后删除
    if (copy_file(src, dest))
    {
        delete_file_physical(src);
        return true;
    }

    return false;
}

// 删除文件
bool delete_file_physical(const char *path)
{
#ifdef _WIN32
    return remove(path) == 0;
#else
    return unlink(path) == 0;
#endif
}